package com.bear.atlassianmcp.jira.service;

import com.bear.atlassianmcp.common.util.SessionUtil;
import com.bear.atlassianmcp.jira.config.JiraProperties;
import com.bear.atlassianmcp.jira.exception.JiraIntegrationException;
import com.bear.atlassianmcp.oauth.context.OAuthContextHolder;
import com.bear.atlassianmcp.oauth.model.OAuthRequestContext;
import com.bear.atlassianmcp.oauth.strategy.AuthenticationStrategy;
import com.bear.atlassianmcp.oauth.strategy.AuthenticationStrategyFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;


/**
 * Jira认证服务
 * 负责处理Jira API的认证相关功能
 * 支持 Basic Auth 和 OAuth 1.0a 两种认证方式
 */
@Service
public class JiraAuthService {

    private static final Logger logger = LoggerFactory.getLogger(JiraAuthService.class);

    private final JiraProperties jiraProperties;
    private final AuthenticationStrategyFactory strategyFactory;

    @Autowired
    public JiraAuthService(JiraProperties jiraProperties, AuthenticationStrategyFactory strategyFactory) {
        this.jiraProperties = jiraProperties;
        this.strategyFactory = strategyFactory;
    }


    /**
     * 创建带有认证信息的HTTP Headers
     * 自动选择合适的认证策略（Basic Auth 或 OAuth 1.0a）
     *
     * @param toolContext 工具上下文，用于获取请求头中的授权信息
     * @return 包含认证信息的HttpHeaders
     * @throws JiraIntegrationException 如果认证失败
     */
    public HttpHeaders createAuthHeaders(ToolContext toolContext) {
        try {
            // 使用策略工厂选择合适的认证策略
            AuthenticationStrategy strategy = strategyFactory.getJiraAuthStrategy(toolContext);

            // 记录使用的认证策略
            logger.debug("Using {} authentication strategy for Jira",
                        strategy.getAuthenticationType());

            return strategy.createAuthHeaders(toolContext);

        } catch (Exception e) {
            logger.error("Failed to create auth headers for Jira: {}", e.getMessage());
            throw JiraIntegrationException.authenticationFailed(
                "Authentication failed: " + e.getMessage());
        }
    }

    /**
     * 创建带有认证信息的HTTP Headers（带请求上下文）
     * 支持 OAuth 1.0a 的精确签名生成
     *
     * @param toolContext 工具上下文
     * @param requestUrl 请求 URL
     * @param httpMethod HTTP 方法
     * @return 包含认证信息的HttpHeaders
     * @throws JiraIntegrationException 如果认证失败
     */
    public HttpHeaders createAuthHeaders(ToolContext toolContext, String requestUrl, String httpMethod) {
        // 设置 OAuth 请求上下文
        OAuthRequestContext oauthContext = OAuthRequestContext.builder()
                .serviceType(AuthenticationStrategy.ServiceType.JIRA)
                .requestUrl(requestUrl)
                .httpMethod(httpMethod)
                .build();

        return OAuthContextHolder.executeWithContext(oauthContext, () ->
             createAuthHeaders(toolContext)
        );
    }

    /**
     * 在指定的 OAuth 上下文中执行操作
     *
     * @param requestUrl 请求 URL
     * @param httpMethod HTTP 方法
     * @param operation 要执行的操作
     * @param <T> 操作返回类型
     * @return 操作结果
     */
    public <T> T executeWithOAuthContext(String requestUrl, String httpMethod,
                                        OAuthContextHolder.ContextOperation<T> operation) {
        OAuthRequestContext context = OAuthRequestContext.builder()
                .serviceType(AuthenticationStrategy.ServiceType.JIRA)
                .requestUrl(requestUrl)
                .httpMethod(httpMethod)
                .build();

        return OAuthContextHolder.executeWithContext(context, operation);
    }

    /**
     * 验证认证配置是否完整
     * 根据启用的认证策略进行相应的配置验证
     *
     * @throws JiraIntegrationException 如果认证配置不完整
     */
    public void validateAuthConfiguration() {
        // 基础配置验证
        if (jiraProperties.getBaseUrl() == null || jiraProperties.getBaseUrl().trim().isEmpty()) {
            throw JiraIntegrationException.authenticationFailed(
                "Jira base URL must be configured");
        }

        try {
            // 使用策略工厂验证认证配置
            AuthenticationStrategy strategy = strategyFactory.getJiraAuthStrategy(null);
            strategy.validateAuthConfiguration();

            logger.info("Jira authentication configuration validated successfully using {}",
                       strategy.getAuthenticationType());

        } catch (Exception e) {
            logger.warn("Authentication strategy validation failed, falling back to basic validation: {}",
                       e.getMessage());

            // 回退到基础的用户名密码验证（向后兼容）
            if (jiraProperties.getUsername() == null || jiraProperties.getUsername().trim().isEmpty()) {
                throw JiraIntegrationException.authenticationFailed(
                    "Jira username must be configured for Basic Auth");
            }

            if (jiraProperties.getPassword() == null || jiraProperties.getPassword().trim().isEmpty()) {
                throw JiraIntegrationException.authenticationFailed(
                    "Jira password must be configured for Basic Auth");
            }

            logger.info("Jira Basic Auth configuration validated successfully");
        }
    }

    /**
     * 获取Jira API基础URL
     * 
     * @return API基础URL
     */
    public String getApiBaseUrl() {
        return jiraProperties.getApiBaseUrl();
    }

    /**
     * 获取当前配置的用户名（用于日志记录）
     *
     * @return 用户名
     */
    public String getCurrentUsername() {
        return jiraProperties.getUsername();
    }

    /**
     * 获取认证策略信息
     *
     * @param toolContext 工具上下文
     * @return 认证策略信息
     */
    public AuthenticationStrategyFactory.AuthStrategyInfo getAuthStrategyInfo(ToolContext toolContext) {
        return strategyFactory.getAuthStrategyInfo(AuthenticationStrategy.ServiceType.JIRA, toolContext);
    }

    /**
     * 强制使用 OAuth 认证策略
     *
     * @return OAuth 认证策略
     */
    public AuthenticationStrategy forceOAuthStrategy() {
        return strategyFactory.forceOAuthStrategy(AuthenticationStrategy.ServiceType.JIRA);
    }

    /**
     * 强制使用 Basic Auth 认证策略
     *
     * @return Basic Auth 认证策略
     */
    public AuthenticationStrategy forceBasicAuthStrategy() {
        return strategyFactory.forceBasicAuthStrategy();
    }

    /**
     * 测试认证连接
     *
     * @param toolContext 工具上下文
     * @return 连接测试结果
     */
    public String testAuthConnection(ToolContext toolContext) {
        try {
            AuthenticationStrategy strategy = strategyFactory.getJiraAuthStrategy(toolContext);
            return strategy.testConnection(toolContext, jiraProperties.getBaseUrl());
        } catch (Exception e) {
            logger.error("Auth connection test failed: {}", e.getMessage());
            throw JiraIntegrationException.authenticationFailed(
                "Connection test failed: " + e.getMessage());
        }
    }

    /**
     * 从ToolContext中获取授权信息（保留用于向后兼容）
     *
     * @param toolContext 工具上下文
     * @return 授权信息，如果获取失败返回null
     * @deprecated 使用 AuthenticationStrategy 替代
     */
    @Deprecated
    private String getAuthorizationFromContext(ToolContext toolContext) {
        if (toolContext == null) {
            logger.error("ToolContext is null, cannot retrieve authorization");
            return null;
        }
        try {
            String authorization = SessionUtil.getAuthorization(toolContext);
            if (authorization != null && authorization.startsWith("Basic ")) {
                logger.debug("Successfully retrieved authorization from request headers");
                return authorization;
            } else if (authorization != null) {
                logger.error("Authorization header found but not in Basic format: {}",
                           authorization.substring(0, Math.min(authorization.length(), 10)) + "...");
                return null;
            } else {
                logger.error("No authorization header found in request");
                return null;
            }
        } catch (Exception e) {
            logger.error("Failed to get authorization from context: {}", e.getMessage());
            return null;
        }
    }
}
